/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package foxmob.mlts.controller.setter;

import foxmob.mlts.component.FileManager;
import foxmob.mlts.interfaces.setter.SetterFormControllerDelegate;
import foxmob.mlts.model.Question;
import foxmob.mlts.model.QuestionPaper;
import foxmob.mlts.model.Section;
import foxmob.mlts.model.Subsection;
import foxmob.mlts.model.TreeObject;
import foxmob.mlts.viewcontroller.marker.MarkAnswerForm;
import foxmob.mlts.viewcontroller.setter.NewTestRecordForm;
import foxmob.mlts.viewcontroller.setter.OpenTestRecordForm;
import foxmob.mlts.viewcontroller.setter.QuestionForm;
import foxmob.mlts.viewcontroller.setter.SectionForm;
import foxmob.mlts.viewcontroller.setter.SetDefaultTestForm;
import foxmob.mlts.viewcontroller.setter.SetterForm;
import foxmob.mlts.viewcontroller.setter.SetterPreviewForm;
import foxmob.mlts.viewcontroller.setter.SubsectionForm;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

/**
 *
 * @author Lunayo
 */
public class SetterFormController implements SetterFormControllerDelegate{
    
    private QuestionPaper testRecord;
    private QuestionForm questionForm;
    private SectionForm sectionForm;
    private SubsectionForm subsectionForm;
    private SetterPreviewForm previewForm;
    private NewTestRecordForm testRecordForm;
    private OpenTestRecordForm openTestRecordForm;
    
    private SetterForm delegate;
    
    public static final int TEST_RECORD_LEVEL = 0;
    public static final int SECTION_LEVEL = 1;
    public static final int SUB_SECTION_LEVEL = 2;
    public static final int QUESTION_LEVEL = 3;

    
    public enum ActionEvent {
        ADD_EVENT, EDIT_EVENT, DELETE_EVENT, MOVE_UP_EVENT, MOVE_DOWN_EVENT
    }
    
    public SetterFormController() {
        initForm();
    }
    
    public void setDelegate(SetterForm delegate) {
        this.delegate = delegate;
    }
    
    private void initForm() {
        this.questionForm = new QuestionForm(this);
        this.subsectionForm = new SubsectionForm(this);
        this.sectionForm = new SectionForm(this);
        this.testRecordForm = new NewTestRecordForm(this);
        this.openTestRecordForm = new OpenTestRecordForm(this);
        this.previewForm = new SetterPreviewForm();
    }
    
    private void loadTestRecord() {
        // iterate test record 
        // to create a tree model
        DefaultMutableTreeNode root = 
            new DefaultMutableTreeNode(testRecord.getTestName());
        for (Section section : testRecord.getSections()) {
            DefaultMutableTreeNode sectionNode =
                    new DefaultMutableTreeNode(section);
            for (Subsection subsection : section.getSubsections()) {
                DefaultMutableTreeNode subsectionNode =
                    new DefaultMutableTreeNode(subsection);
                for (Question question : subsection.getQuestions()) {
                    DefaultMutableTreeNode questionNode =
                        new DefaultMutableTreeNode(question);
                    subsectionNode.add(questionNode);
                }
                sectionNode.add(subsectionNode);
            }
            root.add(sectionNode);
        }
            
        DefaultTreeModel treeModel = new DefaultTreeModel(root);
        delegate.getRecordTree().setModel(treeModel);
    }
    
    public TreeObject getObjectFromTree(DefaultMutableTreeNode object) {
        TreeObject treeObject = new TreeObject();
        int level = object.getLevel();
        FileManager fileManager = FileManager.getInstanceObject();
        if (level == QUESTION_LEVEL) {
            TreeNode subsectionNode = object.getParent();
            TreeNode sectionNode = subsectionNode.getParent();
            TreeNode rootNode = sectionNode.getParent();
            int questionIndex = subsectionNode.getIndex(object);
            int subsectionIndex = sectionNode.getIndex(subsectionNode);
            int sectionIndex = rootNode.getIndex(sectionNode);
            Section section = testRecord.getSections().get(sectionIndex);
            Subsection sub = section.getSubsections().get(subsectionIndex);
            Question question = sub.getQuestions().get(questionIndex);
            
            // create new tree object for passing 
            treeObject.setQuestion(question);
            treeObject.setSection(section);
            treeObject.setSubsection(sub);
            treeObject.setParentNode(object);
            treeObject.setRecord(testRecord);
        } else if (level == SUB_SECTION_LEVEL) {
            TreeNode sectionNode = object.getParent();
            TreeNode rootNode = sectionNode.getParent();
            int subsectionIndex = sectionNode.getIndex(object);
            int sectionIndex = rootNode.getIndex(sectionNode);
            Section section = testRecord.getSections().get(sectionIndex);
            Subsection sub = section.getSubsections().get(subsectionIndex);
            
            // create new tree object for passing
            treeObject.setSection(section);
            treeObject.setSubsection(sub);
            treeObject.setParentNode(object);
            treeObject.setRecord(testRecord);
        } else if (level == SECTION_LEVEL) {
            TreeNode rootNode = object.getParent();
            int sectionIndex = rootNode.getIndex(object);
            Section section = testRecord.getSections().get(sectionIndex);
            
            // create new tree object for passing 
            treeObject.setSection(section);
            treeObject.setRecord(testRecord);
            treeObject.setParentNode(object);
        } else if (level == TEST_RECORD_LEVEL) {
            treeObject.setRecord(testRecord);
            treeObject.setParentNode(object);
        }
        
        return treeObject;
    }
    
    public void changeRecordPosition(ActionEvent status) {
        DefaultMutableTreeNode node = 
                (DefaultMutableTreeNode)delegate.getRecordTree().getLastSelectedPathComponent();
        int level = node.getLevel();
        TreeObject treeObject = getObjectFromTree(node);
        FileManager manager = FileManager.getInstanceObject();
        if (level == QUESTION_LEVEL) {
            TreeNode subsectionNode = node.getParent();
            TreeNode sectionNode = subsectionNode.getParent();
            TreeNode rootNode = sectionNode.getParent();
            Section section =
                testRecord.getSectionWithID(treeObject.getSection().getID());
            Subsection subsection = 
                    section.getSubsectionWithID(treeObject.getSubsection().getID());
            // return earlier
            if (subsection.getQuestionsLength() <= 1) return;
            if (status == ActionEvent.MOVE_UP_EVENT) {
                int questionIndex = subsectionNode.getIndex(node);
                // return earlier
                if (questionIndex <= 0) return;
                Question question =
                    subsection.getQuestions().get(questionIndex);
                Question previousQuestion = 
                    subsection.getQuestions().get(questionIndex - 1);
                // change the order
                subsection.getQuestions().set(questionIndex, previousQuestion);
                subsection.getQuestions().set(questionIndex - 1, question);
            } else if (status == ActionEvent.MOVE_DOWN_EVENT) {
                int questionIndex = subsectionNode.getIndex(node);
                // return earlier
                if (questionIndex >= subsectionNode.getChildCount()-1) return;
                Question question =
                    subsection.getQuestions().get(questionIndex);
                Question nextQuestion = 
                    subsection.getQuestions().get(questionIndex + 1);
                // change the order
                subsection.getQuestions().set(questionIndex, nextQuestion);
                subsection.getQuestions().set(questionIndex + 1, question);
            }
        } else if (level == SUB_SECTION_LEVEL) {
            TreeNode sectionNode = node.getParent();
            TreeNode rootNode = sectionNode.getParent();
            Section section =
                testRecord.getSectionWithID(treeObject.getSection().getID());
            if (section.getSubsectionLength() <= 1) return;
            if (status == ActionEvent.MOVE_UP_EVENT) {
                int subSectionIndex = sectionNode.getIndex(node);
                // return earlier
                if (subSectionIndex <= 0) return;
                Subsection subsection =
                    section.getSubsections().get(subSectionIndex);
                Subsection previousSubsection = 
                    section.getSubsections().get(subSectionIndex - 1);
                // change the order
                section.getSubsections().set(subSectionIndex, previousSubsection);
                section.getSubsections().set(subSectionIndex - 1, subsection);
            } else if (status == ActionEvent.MOVE_DOWN_EVENT) {
                int sectionIndex = sectionNode.getIndex(node);
                // return earlier
                if (sectionIndex >= sectionNode.getChildCount()-1) return;
                Subsection subsection =
                    section.getSubsections().get(sectionIndex);
                Subsection nextSubsection = 
                    section.getSubsections().get(sectionIndex + 1);
                // change the order
                section.getSubsections().set(sectionIndex, nextSubsection);
                section.getSubsections().set(sectionIndex + 1, subsection);
            }
        } else if (level == SECTION_LEVEL) {
            TreeNode rootNode = node.getParent();
            if (testRecord.getSectionsLength() <= 1) return;
            if (status == ActionEvent.MOVE_UP_EVENT) {
                int sectionIndex = rootNode.getIndex(node);
                // return earlier
                if (sectionIndex <= 0) return;
                Section section =
                    testRecord.getSections().get(sectionIndex);
                Section previousSection = 
                    testRecord.getSections().get(sectionIndex - 1);
                // change the order
                testRecord.getSections().set(sectionIndex, previousSection);
                testRecord.getSections().set(sectionIndex - 1, section);
            } else if (status == ActionEvent.MOVE_DOWN_EVENT) {
                int sectionIndex = rootNode.getIndex(node);
                // return earlier
                if (sectionIndex >= rootNode.getChildCount()-1) return;
                Section section =
                    testRecord.getSections().get(sectionIndex);
                Section nextSection = 
                    testRecord.getSections().get(sectionIndex + 1);
                // change the order
                testRecord.getSections().set(sectionIndex, nextSection);
                testRecord.getSections().set(sectionIndex + 1, section);
            }
        }
        try {
            manager.saveToFile(testRecord);
            this.changeNodePositionDidFinish(status);
        } catch (IOException ex) {
            Logger.getLogger(SetterForm.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void deleteRecord(DefaultMutableTreeNode node) {
        int level = node.getLevel();
        TreeObject treeObject = getObjectFromTree(node);
        FileManager manager = FileManager.getInstanceObject();
        if (level == QUESTION_LEVEL) {
            TreeNode subsectionNode = node.getParent();
            TreeNode sectionNode = subsectionNode.getParent();
            TreeNode rootNode = sectionNode.getParent();
            Section section =
                testRecord.getSectionWithID(treeObject.getSection().getID());
            Subsection subsection = 
                    section.getSubsectionWithID(treeObject.getSubsection().getID());
            Question question =
                    subsection.getQuestionWithID(treeObject.getQuestion().getID());
            subsection.removeQuestion(question);
        } else if (level == SUB_SECTION_LEVEL) {
            TreeNode sectionNode = node.getParent();
            TreeNode rootNode = sectionNode.getParent();
            Section section =
                testRecord.getSectionWithID(treeObject.getSection().getID());
            Subsection subsection = 
                    section.getSubsectionWithID(treeObject.getSubsection().getID());
            section.removeSubSection(subsection);
        } else if (level == SECTION_LEVEL) {
            TreeNode rootNode = node.getParent();
            Section section =
                testRecord.getSectionWithID(treeObject.getSection().getID());
            testRecord.removeSection(section);
        }
        try {
            manager.saveToFile(testRecord);
        } catch (IOException ex) {
            Logger.getLogger(SetterForm.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public static TreePath getPath(TreeNode treeNode) {
        ArrayList<Object> nodes = new ArrayList<Object>();
        if (treeNode != null) {
          nodes.add(treeNode);
          treeNode = treeNode.getParent();
          while (treeNode != null) {
            nodes.add(0, treeNode);
            treeNode = treeNode.getParent();
          }
        }

        return nodes.isEmpty() ? null : new TreePath(nodes.toArray());
    }
    
    public Object copySubTree(DefaultMutableTreeNode subRoot, DefaultMutableTreeNode sourceTree) throws CloneNotSupportedException  
    {  
        if (sourceTree == null) {  
            return subRoot;  
        }  
        for (int i = 0; i < sourceTree.getChildCount(); i++) {  
            DefaultMutableTreeNode child = (DefaultMutableTreeNode)sourceTree.getChildAt(i);  
            DefaultMutableTreeNode clone = 
                    new DefaultMutableTreeNode(child.getUserObject()); 
            subRoot.add(clone);  
            copySubTree(clone, child);  
        }  
        return subRoot;  
    } 
    
    public SetterForm getSetterFormDelegate() {
        return this.delegate;
    }
    
    public void recordTreeNodeSelection() {
        DefaultMutableTreeNode node = 
                (DefaultMutableTreeNode)delegate.getRecordTree().getLastSelectedPathComponent();
        if (node == null) return;
        invokeComponent(ActionEvent.EDIT_EVENT);
    }
    
    public void menuItemPreviewDidTap() {
        // return earlier
        if (testRecord.getSectionsLength() == 0) return;
        previewForm.getSetterPreviewFormController().loadSection(testRecord, getCurrentSectionIndex());
        previewForm.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        previewForm.setVisible(true);
    }
    
    public void openMenuItemDidTap() {
        openTestRecordForm.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        openTestRecordForm.getOpenTestRecordFormController().loadTestRecord();
        openTestRecordForm.setVisible(true);
    }
    
    public void newMenuItemDidTap() {
        testRecordForm.getNewTestRecordFormController().setCurrentState(ActionEvent.ADD_EVENT);
        testRecordForm.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        testRecordForm.setVisible(true);
    }
    
    public void arrowButtonUpDidTap() {
        changeRecordPosition(ActionEvent.MOVE_UP_EVENT);
    }
    
    public void arrowButtonDownDidTap() {
        changeRecordPosition(ActionEvent.MOVE_DOWN_EVENT);
    }
    
    public void defaultTestMenuDidTap() {
        SetDefaultTestForm defaultTestForm = new SetDefaultTestForm();
        defaultTestForm.setVisible(true);
        defaultTestForm.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
    }
    
    public void recordTreeMouseDidClick() {
        DefaultMutableTreeNode node = 
                (DefaultMutableTreeNode)delegate.getRecordTree().getLastSelectedPathComponent();
        if (node == null ) return;
        invokeComponent(ActionEvent.EDIT_EVENT);
    }
    
/**
 *
 * @param notification 
 */ 
    @Override
    public void deleteTreeDidFinish(TreeNode node) {
        // Update the JTree model
        DefaultTreeModel model = (DefaultTreeModel)delegate.getRecordTree().getModel();
        DefaultMutableTreeNode child = (DefaultMutableTreeNode)node;
        model.removeNodeFromParent(child);
    }
    
    @Override
    public void addTreeDidFinish(Object treeObject, TreeNode parentNode) {
        // Update the JTree model
        DefaultTreeModel model = (DefaultTreeModel)delegate.getRecordTree().getModel();
        DefaultMutableTreeNode newChild = 
            new DefaultMutableTreeNode(treeObject);
        DefaultMutableTreeNode parent = (DefaultMutableTreeNode)parentNode;
        model.insertNodeInto(newChild,
                              parent,
                              parentNode.getChildCount());
        // move the selection to the new child
        delegate.getRecordTree().setSelectionPath(getPath(parentNode));
        delegate.getRecordTree().expandPath(getPath(parentNode));
    }
    
    @Override
    public void editTreeDidFinish(Object treeObject, TreeNode parentNode) {
        DefaultTreeModel model = (DefaultTreeModel)delegate.getRecordTree().getModel();
        delegate.getRecordTree().updateUI();
        delegate.getRecordTree().repaint();
    }
    
    @Override
    public void changeNodePositionDidFinish(ActionEvent event) {
        if (event == ActionEvent.MOVE_UP_EVENT) {
            DefaultTreeModel model = (DefaultTreeModel)delegate.getRecordTree().getModel();
            DefaultMutableTreeNode node = 
                (DefaultMutableTreeNode)delegate.getRecordTree().getLastSelectedPathComponent();
            DefaultMutableTreeNode cloneNode = (DefaultMutableTreeNode) node.clone();
            try {
                // deep clone the tree
                cloneNode = (DefaultMutableTreeNode) copySubTree(cloneNode, node);
            } catch (CloneNotSupportedException ex) {
                Logger.getLogger(SetterForm.class.getName()).log(Level.SEVERE, null, ex);
            }
            int previousNodeIndex = node.getParent().getIndex(node) - 1;
            DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent();
            DefaultMutableTreeNode parentClone = (DefaultMutableTreeNode) parent.clone();
            model.removeNodeFromParent(node);
            model.insertNodeInto(cloneNode,
                                 parent,
                                 previousNodeIndex);
            // move the selection to the new child
            delegate.getRecordTree().setSelectionPath(getPath(cloneNode));
        } else if (event == ActionEvent.MOVE_DOWN_EVENT) {
            DefaultTreeModel model = (DefaultTreeModel)delegate.getRecordTree().getModel();
            DefaultMutableTreeNode node = 
                (DefaultMutableTreeNode)delegate.getRecordTree().getLastSelectedPathComponent();
            DefaultMutableTreeNode cloneNode = (DefaultMutableTreeNode) node.clone();
            try {
                // deep clone the tree
                cloneNode = (DefaultMutableTreeNode) copySubTree(cloneNode, node);
            } catch (CloneNotSupportedException ex) {
                Logger.getLogger(SetterForm.class.getName()).log(Level.SEVERE, null, ex);
            }
            int nextNodeIndex = node.getParent().getIndex(node) + 1;
            DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent();
            DefaultMutableTreeNode parentClone = (DefaultMutableTreeNode) parent.clone();
            model.removeNodeFromParent(node);
            model.insertNodeInto(cloneNode,
                                 parent,
                                 nextNodeIndex);
            // move the selection to the new child
            delegate.getRecordTree().setSelectionPath(getPath(cloneNode));
        }
        delegate.getRecordTree().updateUI();
    }
    
    @Override
    public void updateUI() {
        delegate.getDetailPanel().repaint();
        delegate.pack();
    }
    
    @Override
    public void openRecordDidFinish(QuestionPaper testRecord) {
        this.testRecord = testRecord;
        loadTestRecord();
    }
    
 /**
 *
 *  end of notification
 */
    
    @Override
    public void invokeComponent(ActionEvent status) {
        DefaultMutableTreeNode node = 
                (DefaultMutableTreeNode)delegate.getRecordTree().getLastSelectedPathComponent();
        int level = node.getLevel();
        TreeObject treeObject = getObjectFromTree(node);
        // Hide all form at first
        
        if (status == ActionEvent.ADD_EVENT) {
            // If event is add event
            // the component will only trigger add form
            // when the level is up one level
            level += 1;
            // reset all component
            questionForm.getQuestionFormController().resetInputComponent();
            subsectionForm.getSubsectionFormController().resetInputComponent();
            sectionForm.getSectionFormController().resetInputComponent();
        }
        if (level == QUESTION_LEVEL) {
            if (status != ActionEvent.DELETE_EVENT) {
                questionForm.getQuestionFormController().setTreeObject(treeObject);
                questionForm.getQuestionFormController().setCurrentState(ActionEvent.ADD_EVENT);
                // update the combo box component
                questionForm.getQuestionFormController().updateQuestionComponents(treeObject);
                if (status == ActionEvent.EDIT_EVENT) {
                    // fill in the text box
                    questionForm.getQuestionFormController().fillQuestionComponents(treeObject);
                    questionForm.getQuestionFormController().setCurrentState(ActionEvent.EDIT_EVENT);
                }
                delegate.getDetailPanel().removeAll();
                delegate.getDetailPanel().add(questionForm.getQuestionFormController().getDelegate().getContentPane());
                delegate.pack();
            }
        } else if (level == SUB_SECTION_LEVEL) {
            if (status != ActionEvent.DELETE_EVENT) {
                subsectionForm.getSubsectionFormController().setTreeObject(treeObject);
                subsectionForm.getSubsectionFormController().setCurrentState(ActionEvent.ADD_EVENT);
                if (status == ActionEvent.EDIT_EVENT) {
                    // fill in the text box
                    subsectionForm.getSubsectionFormController().fillSubsectionComponents(treeObject);
                    subsectionForm.getSubsectionFormController().setCurrentState(ActionEvent.EDIT_EVENT);
                }
                delegate.getDetailPanel().removeAll();
                delegate.getDetailPanel().add(subsectionForm.getContentPane());
                delegate.pack();
            }
        } else if (level == SECTION_LEVEL) {
            if (status != ActionEvent.DELETE_EVENT) {
                sectionForm.getSectionFormController().setTreeObject(treeObject);
                sectionForm.getSectionFormController().setCurrentState(ActionEvent.ADD_EVENT);
                if (status == ActionEvent.EDIT_EVENT) {
                    // fill in the text box
                    sectionForm.getSectionFormController().fillSectionComponents(treeObject);
                    sectionForm.getSectionFormController().setCurrentState(ActionEvent.EDIT_EVENT);
                }
                delegate.getDetailPanel().removeAll();
                delegate.getDetailPanel().add(sectionForm.getContentPane());
                delegate.pack();
            }
        } else if (level == TEST_RECORD_LEVEL) {
            if (status != ActionEvent.DELETE_EVENT) {
                testRecordForm.getNewTestRecordFormController().setTreeObject(treeObject);
                testRecordForm.getNewTestRecordFormController().setCurrentState(ActionEvent.ADD_EVENT);
                if (status == ActionEvent.EDIT_EVENT) {
                    // fill in the text box
                    testRecordForm.getNewTestRecordFormController().fillTestRecordComponents(treeObject);
                    testRecordForm.getNewTestRecordFormController().setCurrentState(ActionEvent.EDIT_EVENT);
                }
                delegate.getDetailPanel().removeAll();
                delegate.getDetailPanel().add(testRecordForm.getContentPane());
                delegate.pack();
            }
        }
        
        // if delete event
        if (status == ActionEvent.DELETE_EVENT) {
            // Confimation box
            int response = JOptionPane.showConfirmDialog(null, 
                    "Are you sure you want to delete ?"
                    + "\nAll of the children will also be deleted", 
                    "Confirm",
                JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
            if (response == JOptionPane.YES_OPTION) {
                deleteRecord(node);
                // notify the finish method
                deleteTreeDidFinish(node);
            }
        }
    }
    
    public int getCurrentSectionIndex() {
        // Searching for selected section Index
        DefaultMutableTreeNode object = 
                (DefaultMutableTreeNode)delegate.getRecordTree().getLastSelectedPathComponent();
        int level = 0;
        int sectionIndex = 0;
        if (object == null) return sectionIndex;
        level = object.getLevel();
        if (level == QUESTION_LEVEL) {
            TreeNode subsectionNode = object.getParent();
            TreeNode sectionNode = subsectionNode.getParent();
            TreeNode rootNode = sectionNode.getParent();
            int questionIndex = subsectionNode.getIndex(object);
            int subsectionIndex = sectionNode.getIndex(subsectionNode);
            sectionIndex = rootNode.getIndex(sectionNode);
        } else if (level == SUB_SECTION_LEVEL) {
            TreeNode sectionNode = object.getParent();
            TreeNode rootNode = sectionNode.getParent();
            int subsectionIndex = sectionNode.getIndex(object);
            sectionIndex = rootNode.getIndex(sectionNode);
        } else if (level == SECTION_LEVEL) {
            TreeNode rootNode = object.getParent();
            sectionIndex = rootNode.getIndex(object);        
        } 
        return sectionIndex;
    }
}
